package com.invengo.base.http;


import com.invengo.library_db.entity.module_robot.RobotTokenBean;
import com.trello.rxlifecycle2.LifecycleProvider;
import com.trello.rxlifecycle2.LifecycleTransformer;

import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import me.goldze.mvvmhabit.base.BaseViewModel;
import me.goldze.mvvmhabit.http.ExceptionHandle;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import retrofit2.HttpException;

public class RobotRxUtils {

    public static class HandleFuc<T> implements Function<RobotBaseBean<T>, T> {
        public T apply(RobotBaseBean<T> response) {
            if (!response.isSuccess()) {
                throw new IllegalArgumentException("数据异常");
            } else {
                return response.getResult();
            }
        }
    }


    public static class RetryWithNewToken implements Function<Observable<Throwable>, ObservableSource<?>> {

        private int maxRetry;
        private int delay;
        private int retryCount = 0;

        public RetryWithNewToken(int maxRetry, int delay) {

        }

        private Observable<RobotBaseBean<RobotTokenBean>> tokenObservable;


        public RetryWithNewToken(Observable<RobotBaseBean<RobotTokenBean>> observable, int maxRetry, int delay) {
            this.tokenObservable = observable;
            this.maxRetry = maxRetry;
            this.delay = delay;
            retryCount = 0;
        }

        @Override
        public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
            return throwableObservable.flatMap(throwable -> {
                if (throwable instanceof HttpException) {
                    if (((HttpException) throwable).code() == 401) {
                        if (++retryCount <= maxRetry) {
                            return tokenObservable.flatMap(robotTokenBeanRobotBaseBean -> {
                                if (robotTokenBeanRobotBaseBean.isSuccess() && robotTokenBeanRobotBaseBean.getResult() != null) {
                                    ACache.getInstance().put("ROBOT_TOKEN", robotTokenBeanRobotBaseBean.getResult().getAccessToken());
                                    return Observable.timer(delay, TimeUnit.MILLISECONDS);
                                } else {
                                    return Observable.error(throwable);
                                }
                            }).subscribeOn(Schedulers.io());
                        } else {
                            return null;
                        }
                    } else {
                        return Observable.error(throwable);
                    }
                } else {
                    return Observable.error(throwable);
                }
            }).subscribeOn(Schedulers.io());
        }
    }


    public static <T> ObservableTransformer<RobotBaseBean<T>, T> applySchedulers(@NonNull LifecycleProvider lifecycle, BaseViewModel vm, boolean showLoading) {
        return observable -> observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(tBaseBean -> {
                    if (showLoading)
                        vm.getUC().getShowRobotLoadingEvent().call();
                })
                .doFinally(() -> {
                    if (showLoading)
                        vm.getUC().getHideRobotLoadingEvent().call();
                })
                .observeOn(Schedulers.io())
                .compose(bindToLifecycle(lifecycle))
                .map(new RobotRxUtils.HandleFuc<T>())
                .onErrorResumeNext((Function<Throwable, Observable<T>>) t -> {
                    t.printStackTrace();
                    return Observable.error(ExceptionHandle.handleException(t));
                })
                .observeOn(AndroidSchedulers.mainThread())
                .doOnError(throwable -> {
                    vm.getUC().getHideRobotLoadingEvent().call();
                    showToast(throwable);
                });
    }

    private static void showToast(Throwable throwable) {
        if (throwable instanceof ExceptionHandle.ResponeThrowable) {
            ToastUtils.showShort(((ExceptionHandle.ResponeThrowable) throwable).message);
        } else {
            ToastUtils.showShort(throwable.getMessage());
        }
    }


    public static <T> LifecycleTransformer<T> bindToLifecycle(@NonNull LifecycleProvider lifecycle) {
        return lifecycle.bindToLifecycle();
    }


}
